#include "Hint.h"
#include "HintConfig.h"
#include <sc95f_pwm.h>

#define HAS_PWM1 (defined(SC95FWxx))

static bool sound;

static uint8_t _getPWMx_Type(uint8_t PWMxy)
{
    return (PWMxy >> 4);
}

static uint8_t _getPWMx(uint8_t PWMxy)
{
    uint8_t x = (PWMxy >> 4);
    return (1 << x);
}

static void _beep_get(uint16_t* PWM_Period, PWM_PresSel_TypeDef* PWM_PRESSEL_FHRC, uint32_t freq)
{
    uint8_t PWMx_Type = _getPWMx_Type(BEEP_PWM);
    switch (PWMx_Type)
    {
    case 0:
        *PWM_Period = 4000000/freq;
        *PWM_PRESSEL_FHRC = PWM0_PRESSEL_FHRC_D8;
        break;
    #if HAS_PWM1
    case 1:
        *PWM_Period = 4000000/freq;
        *PWM_PRESSEL_FHRC = PWM1_PRESSEL_FHRC_D8;
        break;
    #endif
    case 2:
        *PWM_Period = 32000000/freq;
        *PWM_PRESSEL_FHRC = PWM2_PRESSEL_FHRC_D1;
        break;
    case 3:
        *PWM_Period = 32000000/freq;
        *PWM_PRESSEL_FHRC = PWM3_PRESSEL_FHRC_D1;
        break;
    }
}

static void _beep_init()
{
    uint16_t PWM_Period;
    PWM_PresSel_TypeDef PWM_PRESSEL_FHRC;
    _beep_get(&PWM_Period, &PWM_PRESSEL_FHRC, BEEP_FREQ);

    PWM_Init(PWM_PRESSEL_FHRC, PWM_Period);
    PWM_OutputStateConfig(BEEP_PWM, PWM_OUTPUTSTATE_ENABLE);
    PWM_PolarityConfig(BEEP_PWM, PWM_POLARITY_NON_INVERT);
    PWM_IndependentModeConfig(BEEP_PWM, PWM_Period/2);
    // PWM_FaultDetectionConfigEX(PWMx_Type, DISABLE);
    // PWM_ITConfigEX(PWMx_Type, DISABLE, LOW);
}

/**
 * @brief 初始化状态提示指示灯
 * 
 */
void Hint_init()
{
    GPIO_Init(NETWORK_CONNECT_Port, NETWORK_CONNECT_Pin, GPIO_MODE_OUT_PP);
    GPIO_Init(NO_WATER_Port, NO_WATER_Pin, GPIO_MODE_OUT_PP);
    GPIO_Init(NO_FOOD_Port, NO_FOOD_Pin, GPIO_MODE_OUT_PP);
    _beep_init();
    sound = 0;
}

static void _GPIO_set(GPIO_TypeDef GPIOx, uint8_t PortPins, bool state)
{
    if(state)
    {
        GPIO_WriteHigh(GPIOx, PortPins);
    }
    else
    {
        GPIO_WriteLow(GPIOx, PortPins);
    }
}

/**
 * @brief 设置指示灯状态
 * 
 * @param hint 指示灯类型: NETWORK_CONNECT, NO_FOOD, NO_WATER
 * @param state 状态: ture/false
 */
void Hint_set(Hint_State hint , bool state)
{
    switch (hint)
    {
    case NETWORK_CONNECT:
        _GPIO_set(NETWORK_CONNECT_Port, NETWORK_CONNECT_Pin, state);
        break;
    case NO_FOOD:
        _GPIO_set(NO_FOOD_Port, NO_FOOD_Pin, state);
        break;
    case NO_WATER:
        _GPIO_set(NO_WATER_Port, NO_WATER_Pin, state);
        break;
    }
}

void Hint_sound(FunctionalState state)
{
    uint16_t PWM_Period;
    PWM_PresSel_TypeDef PWM_PRESSEL_FHRC;
    _beep_get(&PWM_Period, &PWM_PRESSEL_FHRC, BEEP_FREQ);
    if(!sound)
    {
        state = false;
    }
    PWM_Init(PWM_PRESSEL_FHRC, PWM_Period);
    PWM_IndependentModeConfig(BEEP_PWM, PWM_Period/2);
    PWM_CmdEX(_getPWMx_Type(BEEP_PWM), state);
}

void Hint_music(uint8_t i, bool up)
{
    uint16_t period;
    PWM_PresSel_TypeDef PWM_PRESSEL_FHRC;
    if(up)
        _beep_get(&period, &PWM_PRESSEL_FHRC, music_freq[i]);
    else
        _beep_get(&period, &PWM_PRESSEL_FHRC, music_freq[3 - i]);
    PWM_Init(PWM_PRESSEL_FHRC, period);
    PWM_IndependentModeConfig(BEEP_PWM, period/2);
    PWM_CmdEX(_getPWMx_Type(BEEP_PWM), sound);
}

void Hint_soundShift()
{
    sound = !sound;
}
